package com.tianji.learning.service.impl;

import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.leanring.LearningLessonDTO;
import com.tianji.api.dto.leanring.LearningRecordDTO;
import com.tianji.common.exceptions.DbException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.LearningRecordFormDTO;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.SectionType;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import com.tianji.learning.service.ILearningRecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.learning.utils.LearningRecordDelayTaskHandler;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;

/**
 * <p>
 * 学习记录表 服务实现类
 * </p>
 *
 * @author zhongweiwei
 * @since 2023-05-26
 */
@RequiredArgsConstructor
@Service
public class LearningRecordServiceImpl extends ServiceImpl<LearningRecordMapper, LearningRecord> implements ILearningRecordService {

    private final ILearningLessonService lessonService;

    private final CourseClient courseClient;
    private final LearningRecordDelayTaskHandler taskHandler;

    /**
     * 查询指定课程的学习记录
     *
     * @param courseId
     * @return
     */
    @Override
    public LearningLessonDTO queryLearningRecordsByCourseId(Long courseId) {
        //1-获取用户id
        Long userId = UserContext.getUser();
        //2-查询课表
        LearningLesson lesson = lessonService.queryLessonByUserIdorCourseid(userId, courseId);
        //3-根据课表id查出相关记录
        List<LearningRecord> recordList = lambdaQuery().eq(LearningRecord::getLessonId, lesson.getId()).list();
        //4-封装结果
        LearningLessonDTO learningLessonDTO = new LearningLessonDTO();
        learningLessonDTO.setId(lesson.getId());
        learningLessonDTO.setLatestSectionId(lesson.getLatestSectionId());
        learningLessonDTO.setRecords(BeanUtils.copyList(recordList, LearningRecordDTO.class));
        return learningLessonDTO;
    }

    /**
     * 提交学习记录
     *
     * @param formDTO
     */
    @Override
    public void submitLearningRecord(LearningRecordFormDTO formDTO) {
        //1-获取用户id
        Long userId = UserContext.getUser();
        //小节内容是否学完的标记默认为fales
        Boolean finished = false;
        //2判断小节内容
        if (formDTO.getSectionType() == SectionType.VIDEO) {
            //处理视频记录
            finished = processingVideoRecording(userId, formDTO);
        } else {
            //处理考试记录
            finished = processingExamRecord(userId, formDTO);
        }
        //处理课表数据
        processScheduleData(finished, formDTO);
    }

    private void processScheduleData(Boolean finished, LearningRecordFormDTO formDTO) {
        //1-根据次课程id查询课程的课程表
        LearningLesson lesson = lessonService.getById(formDTO.getLessonId());
        if (BeanUtils.isEmpty(lesson)) {
            throw new RuntimeException("课程信息不存在");
        }
        //判断是否有新的已完成的小节
        Boolean finishBar = false;
        //根据课程id查询课程信息
        CourseFullInfoDTO courseInfo = courseClient.getCourseInfoById(lesson.getCourseId(), false, false);
        if (!BeanUtils.isEmpty(courseInfo)) {
            throw new RuntimeException("课程信息不存在");
        }
        //如果当前课成以学完的小节数量加上新增的一个完成的小节数量大于或等于了课程的小节总数则改变该课程的状态为已学完
        finishBar = lesson.getLearnedSections() + 1 >= courseInfo.getSectionNum();
        // 3-是，修改课程表数据
        lessonService.lambdaUpdate()
                .set(lesson.getLearnedSections() == 0, LearningLesson::getStatus, LessonStatus.LEARNING.getValue())
                .set(finishBar, LearningLesson::getStatus, LessonStatus.FINISHED.getValue())
                .setSql("learned_sections=learned_sections+1")
                .eq(LearningLesson::getId, lesson.getId())
                .update();


    }

    private Boolean processingVideoRecording(Long userId, LearningRecordFormDTO formDTO) {
        //1判断当前视频是否有学习记录，如果没有则直接添加
        LearningRecord old = queryOldRecord(formDTO.getLessonId(), formDTO.getSectionId());
        if (old == null) {
            // 如果当前视频没有学习记录，那么直接添加记录
            LearningRecord learningRecord = BeanUtils.copyBean(formDTO, LearningRecord.class);
            learningRecord.setUserId(userId);
            boolean success = save(learningRecord);
            if (!success) {
                throw new RuntimeException("添加记录失败");
            }
            return false;
        }
        //如果记录存在则修改记录并且判断该小节的播放进度是否超过50%，如果超过则课表的已完成小节字段数量加1，
        //再判断该课程的小节完成量是否等于该课程所有小节的数量，如果达标则将课程的状态置为完成；

        boolean finished = !old.getFinished() && formDTO.getMoment() * 2 >= formDTO.getDuration();
        if(!finished){
            LearningRecord record = new LearningRecord();
            record.setLessonId(formDTO.getLessonId());
            record.setSectionId(formDTO.getSectionId());
            record.setMoment(formDTO.getMoment());
            record.setId(old.getId());
            record.setFinished(old.getFinished());
            taskHandler.addLearningRecordTask(record);
            return false;
        }
        //2更新数据
        boolean success = lambdaUpdate()
                .set(LearningRecord::getMoment, formDTO.getMoment())
                .set(LearningRecord::getFinished, true)
                .set(LearningRecord::getFinishTime, formDTO.getCommitTime())
                .eq(LearningRecord::getId, old.getId())
                .update();
        if(!success){
            throw new RuntimeException("更新学习记录失败！");
        }
        //3清理缓存
        taskHandler.cleanRecordCache(formDTO.getLessonId(), formDTO.getSectionId());
        return true;
    }


    /**
     * 根据课程id和小节id查询这个小节的学习记录
     *
     * @param lessonId
     * @param sectionId
     * @return
     */
    private LearningRecord queryOldRecord(Long lessonId, Long sectionId) {
        // 1.查询缓存
        LearningRecord record = taskHandler.readRecordCache(lessonId, sectionId);
        // 2.如果命中，直接返回
        if (record != null) {
            return record;
        }
        // 3.未命中，查询数据库
        record = lambdaQuery()
                .eq(LearningRecord::getLessonId, lessonId)
                .eq(LearningRecord::getSectionId, sectionId)
                .one();
        // 4.写入缓存
        taskHandler.writeRecordCache(record);
        return record;
    }

    private Boolean processingExamRecord(Long userId, LearningRecordFormDTO formDTO) {
        //1-将dto转为实体
        LearningRecord learningRecord = BeanUtils.copyProperties(formDTO, LearningRecord.class);
        learningRecord.setUserId(userId);
        learningRecord.setFinished(true);
        learningRecord.setFinishTime(formDTO.getCommitTime());
        // 2-保存记录到数据库
        boolean success = save(learningRecord);
        // 3-判断是否第一次提交
        if (!success) {
            throw new RuntimeException("新增考试记录失败");
        }
        return true;
    }
}
